home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / httpd / support / WebReport < prev   
Encoding:
Text File  |  1995-05-09  |  32.2 KB  |  1,061 lines

  1. #!/usr/local/bin/perl
  2.  
  3. # Written by: Eric Katz
  4. # email:      ekatz@ncsa.uiuc.edu
  5. #########################################################################
  6. #  Permission is granted to anyone to use this software for any purpose on
  7. #  any computer, and to alter it for your personal use.  Please do not
  8. #  distribute any alterations.
  9. #
  10. #  0. This software is provided "as is" and without any express or implied
  11. #     warranties, including, without limitation, the implied warranties of
  12. #     merchantability and fitness for a particular purpose.
  13. #
  14. #  1. The author is not responsible for the consequences of the use of this
  15. #     software, no matter how deleterious, even if they arise from flaws in it.
  16. #
  17. #  2. The origin of this software must not be misrepresented, either by
  18. #     explicit claim or by omission.
  19. #
  20. #  3. This software may not be sold.
  21. #
  22. #  4. This notice may not be removed or altered.
  23. #
  24. #########################################################################
  25. # To install - Please remove everthing above the #! line.
  26. # Change the perl path to reflect the location of your perl installation.  
  27. # Then answer the following questions.
  28.  
  29. # What is the Name of your server? (Not necessary if ServerName is 
  30. # defined in your httpd.conf file.
  31. $WebServer = www.ncsa.uiuc.edu;
  32.  
  33. # What directory holds your configuration files?
  34. $CONF_PATH = "/web1/http/conf";
  35.  
  36. # If you are generating/maintaining HTML Reports what is the Menu Document
  37. # called?  Set this to "/dev/null" if you don't want to maintain a menu doc.
  38. $MenuDoc = "/General/WebReports.html";
  39.  
  40. # In which directory do you want the output file placed?
  41. $Output_Path = "/tmp";
  42.  
  43. ######################################################################
  44. # DO NOT CHANGE ANTHING BELOW THIS LINE FOR DISTRIBUTION. 
  45. # You make may changes for your personal use but DO NO DISTRIBUTE YOUR
  46. # CHANGES.
  47. #
  48. # REVISION HISTORY
  49. # V1.0 Released 10/2/93
  50. # V1.1 Release 09/29/93
  51. #      Hyperlinks now relative to the Root of the Web Server.
  52. #      Thanks to Mark Scott.
  53. # V1.2 Added -V: Verbose output of progress through log during run.
  54. # V1.1 Release 10/05/93
  55. # V2.0 Changed default to verbose.  Now -n option supresses output
  56. #      for use in crontabs
  57. # V2.1 Released 12/11/93
  58. #      Made many changes to make compatible with new release of NCSA_HTTPD
  59. #      Unfortunately this kludged version wasn't very stable or robust.
  60. # V2.2 Released 1/21/94
  61. #      Completely rewritten to accomodate new features inherent in current
  62. #      releases of NCSA_HTTPD
  63. ######################################################################
  64.  
  65. sub USAGE {
  66. print "USAGE: WebReport [-adtfhe] [-H] [-s] [-vN] [-n] [-l logname] 
  67.                         [-o output directory] [keys]
  68.     a    All
  69.     d    Daily
  70.     t    Time
  71.     f    Files
  72.     h    Host
  73.     e     Errors
  74.     s    Summary
  75.     l    Name of the log file
  76.     o    Location of the output file
  77.     H    Print in html format
  78.     vN    Report Verbosity
  79.     n    Supress Program Verbosity
  80.     D    Current Day only\n";
  81. print "    keys    To limit the report to specific days, times, files, and/or
  82.         hosts.  Any combination of keys may be specified.  See
  83.         examples below.
  84.         Use the following conventions for the best results:
  85.         Search for a date:   'nn'    ie: 10
  86.         Search for a time:   'nn:'    ie: 10:
  87.         Search for a Day:    'Xxx'    ie: Sun or Sunday
  88.         Search for a file:   'xxx'    ie: software
  89.         or             'xx/'        you may need a leading
  90.         or             '/xx'        or trailing '/'
  91.         Search for a domain: '.xxx'    ie: .edu or ncsa.\n";
  92. print "        WebReport will try to 'do the right thing' but it is safer
  93.         to limit the type of search by using one of the -d, -t,
  94.         -f, or -h flags.
  95.  
  96.  
  97.      EXAMPLES:
  98.             WebReport -f Thu Friday 10 11 14 15 Software
  99.                 Will report on the number of people who
  100.                 accessed the Software files on Thursday
  101.                 and Friday during the 10am, 11am, 2pm, 
  102.                 and 4pm hours.
  103.             WebReport -f edu
  104.                 Will report on file accesses that have
  105.                 the edu substring in them.
  106.             WebReport -h .edu
  107.                 Will report on hosts with edu in the name.\n";
  108. print "            WebReport -Hneshfl /var/log/access_log
  109.                                 Will silently generate an error report, 
  110.                 a summary report, a host access report, and a 
  111.                 file access report -- all in html format, and
  112.                                 will automatically update an html Menu
  113.                                 document with links to these reports.\n\n";
  114.  
  115.         exit;
  116. }
  117.  
  118.  
  119.  
  120. require 'getopts.pl';
  121. require 'ctime.pl';
  122.  
  123. # For now the only date information that is needed is the third field
  124. # regardless of whether it is a BSD system or not but we never know
  125. # what the future holds so I included the following subroutines.
  126. if (-e "/vmunix") {
  127.         $BSD = "true";
  128.         }
  129. else {
  130.         $BSD = "false";
  131. }
  132.  
  133. # Get the current time and format it:
  134. $DATE=&ctime(time),"\n";
  135. if ($BSD eq "true") {
  136.         ($day, $month, $date, $time, $year) = split (" ",$DATE);
  137. }
  138. else {
  139.         ($day, $month, $date, $time, $TZ, $year) = split (" ",$DATE);
  140. }
  141.  
  142. &Getopts('VadDtfhesHMnl:o:v:');
  143.  
  144. if ($opt_V) {
  145. print "WARNING: -V is no longer a valid option.  Default is verbose.
  146. Use -n if you wish to supress output\n";
  147. $USAGE;
  148. }
  149.  
  150. if ($opt_M) {
  151. print "WARNING: -M is no longer a valid option.  If -H option is used,
  152. then the Menu Document will be updated automatically.\n";
  153. $USAGE;
  154. }
  155.  
  156. $silent = 1 if ($opt_n);
  157.  
  158. # Print Usage If no options are passed on the command line.
  159. &USAGE if (!($opt_d) &! ($opt_t) &! ($opt_f) &! ($opt_e) &! ($opt_h) &! ($opt_s) &! ($opt_a) &! ($opt_D)); 
  160.  
  161. # If an alternate logfile has been requested
  162. if (defined $opt_l) {
  163.     $TransferLog = $opt_l;
  164. }
  165.  
  166. # If an alternate output directory has been requested
  167. if (defined $opt_o) {
  168.     $Output_Path = $opt_o;
  169.     chop $Output_Path if ($Output_Path =~ /\n/);
  170.     chop $Output_Path if ($Output_Path =~ /\/$/);
  171. }
  172.  
  173.  
  174. # If you want a printout for today only
  175. if ($opt_D) {
  176. $SearchDate = "\\b" . $date . "\\b" . "|";
  177. $SearchDescriptor = $SearchDescriptor . "Today, ";
  178. }
  179.  
  180. # If there are no search key limiters.
  181. if (($#ARGV < 0) &! ($opt_D)) {
  182.     $NO_KEY = 1;
  183.     $NO_DAY_KEY = 1;
  184.     $NO_TIME_KEY = 1;
  185.     $NO_HOST_KEY = 1;
  186.     $NO_OTHERS_KEY = 1;
  187. }
  188.  
  189. # Else create the 'or' pattern matching string
  190. else {
  191.     for ($i=0;$i<=$#ARGV;$i++) {
  192.         if ($ARGV[$i] =~ /Mon|Tue|Wed|Thu|Fri|Sat|Sun/) {
  193.             $SearchDay = $SearchDay . $ARGV[$i] . "|";
  194.             $SearchDescriptor = $SearchDescriptor . "Day: " . $ARGV[$i] . ", ";
  195.         }
  196.         elsif ($ARGV[$i] =~ /\d+:/) {
  197.             chop $ARGV[$i];
  198.             #chop $ARGV[$i] if ($ARGV[$i] =~ /\n/);
  199.             $SearchTime = $SearchTime . $ARGV[$i] . "|";
  200.             $SearchDescriptor = $SearchDescriptor . "Time: " . $ARGV[$i] . ":00" . ", ";
  201.         }
  202.         elsif ($ARGV[$i] =~ /\./) {
  203.             #chop $ARGV[$i];
  204.             $SearchHost = $SearchHost . $ARGV[$i] . "|";
  205.             $SearchDescriptor = $SearchDescriptor . "Host: " . $ARGV[$i] . ", ";
  206.         }
  207.         elsif ($ARGV[$i] =~ /\d+/) {
  208.         die "This does not make sense with the -D option\n" if ($opt_D);
  209.         $SearchDate = $SearchDate . "\\b" . $ARGV[$i] . "\\b" . "|";
  210.         $SearchDescriptor = $SearchDescriptor . "Date: " . $ARGV[$i] . ", ";
  211.         }
  212.         else {
  213.             $SearchOthers = $SearchOthers . $ARGV[$i] . "|";
  214.             $SearchDescriptor = $SearchDescriptor . "Others: " . $ARGV[$i] . ", ";
  215.         }
  216.     }
  217. }
  218. if (defined $SearchDay) {
  219.     chop ($SearchDay);
  220. }
  221. else {
  222.     $NO_DAY_KEY = 1;
  223. }
  224. if (defined $SearchDate) {
  225.     chop ($SearchDate);
  226. }
  227. else {
  228.     $NO_DATE_KEY = 1;
  229. }
  230. if (defined $SearchTime) {
  231.     chop ($SearchTime);
  232. }
  233. else {
  234.     $NO_TIME_KEY = 1;
  235. }
  236. if (defined $SearchHost) {
  237.     chop ($SearchHost);
  238. # We need to escape possible wildcard characters in this string, then
  239. # unescape the 'or' character
  240.     $SearchHost =~ s/\W/\\$&/g;
  241.     $SearchHost =~ s/\\\|/\|/g;
  242. }
  243. else {
  244.     $NO_HOST_KEY = 1;
  245. }
  246. if (defined $SearchOthers) {
  247.     chop ($SearchOthers);
  248.  
  249. # We need to escape possible wildcard characters in this string, then
  250. # unescape the 'or' character
  251.     $SearchOthers =~ s/\W/\\$&/g;
  252.     $SearchOthers =~ s/\\\|/\|/g;
  253. }
  254. else {
  255.     $NO_OTHERS_KEY = 1;
  256. }
  257.  
  258. # Examine httpd.conf
  259. open (HTTP_CONF,"$CONF_PATH/httpd.conf") || die "Couldn't open $CONF_PATH/httpd.conf\n"; 
  260. while (<HTTP_CONF>) {
  261.     chop if (/\n/);
  262.     if (!(/\#/)) {
  263.     ($AdminHeading,$ServerAdmin) = split (/ /) if (/ServerAdmin/) &! (/\#/);
  264.     ($ServerHeading,$WebServer) = split (/ /) if (/ServerName/);
  265.     ($RootHeading,$ServerRoot) = split (/ /) if (/ServerRoot/);
  266.     ($ErrorHeading,$ErrorLog) = split (/ /) if (/ErrorLog/);
  267.     ($TransferHeading,$TransferLog) = split (/ /) if ((/TransferLog/) &! (defined $opt_l));
  268.     ($PidHeading,$PidFile) = split (/ /) if (/ PidFile/);
  269.     ($AccessHeading,$AccessConf) = split (/ /) if (/ AccessConfig/);
  270.     ($SRMHeading,$SRMConf) = split (/ /) if (/ ResourceConfig/);
  271.     
  272.     }
  273. }
  274.  
  275. $ServerRoot = "/usr/local/httpd" if (!(defined $ServerRoot));
  276.  
  277. if (defined $ErrorLog) {
  278.     $ErrorLog = "$ServerRoot/$ErrorLog" if ($ErrorLog !~ /^\//);
  279. }
  280. else {
  281.     $ErrorLog = "$ServerRoot/logs/error_log";
  282. }
  283.  
  284. if (defined $TransferLog) {
  285.     $TransferLog = "$ServerRoot/$TransferLog" if (($TransferLog !~ /^\//) &! ($opt_l));
  286. }
  287. else {
  288.     $TransferLog = "$ServerRoot/logs/access_log";
  289. }
  290.  
  291. if (defined $PidFile) {
  292.     $PidFile = "$ServerRoot/$PidFile" if ($PidFile !~ /^\//);
  293. }
  294. else {
  295.     $PidFile = "$ServerRoot/logs/pid.httpd";
  296. }
  297. if (defined $AccessConf) {
  298.     $AccessConf = "$ServerRoot/$AccessConf" if ($AccessConf !~ /^\//);
  299. }
  300. else {
  301.     $AccessConf = "$ServerRoot/conf/access.conf";
  302. }
  303.  
  304. if (defined $SRMConf) {
  305.     $SRMConf = "$ServerRoot/$SRMConf" if ($SRMConf !~ /^\//);
  306. }
  307. else {
  308.     $SRMConf = "$ServerRoot/conf/srm.conf";
  309. }
  310. close HTTP_CONF;
  311.  
  312. #Examine srm.conf
  313. open (SRM_CONF,"$SRMConf") || die "Couldn't open $SRMConf\n"; 
  314. while (<SRM_CONF>) {
  315. chop if (/\n/);
  316.     if (!(/\#/)) {
  317. # Define root alias
  318.     ($RootHeading,$DocumentRoot) = split (/ /,$_) if (/DocumentRoot/);
  319.     ($UserHeading,$UserDir) = split (/ /,$_) if (/UserDir/);
  320.     ($IndexHeading,$DirIndex) = split (/ /,$_) if (/DirectoryIndex/);
  321.     if ((/Redirect/) &! (/\#/)){
  322.         ($RedirectHeading,$LocalFile,$RDFile) = split (/ /);
  323.         $RDFILES{$LocalFile} = $RDFile;
  324.     }
  325.      if ((/Alias/) &! (/\#/)){
  326.          ($AliasHeading,$AliasName,$RealName) = split (/ /);
  327.          $RealName = "$ServerRoot/$RealName" if ($RealName !~ /^\//);
  328.         chop ($RealName) if ($RealName =~ /\/$/);
  329.          $REALNAME{$AliasName} = $RealName;
  330.     }
  331.     
  332.     }
  333. }
  334.  
  335. @AKA = keys(%REALNAME);
  336. @GO_HTTP = keys(%RDFILES);
  337. $Output_Path = "$DocumentRoot/$Output_Path" if ($Output_Path !~ /^\//);
  338.     
  339.  
  340. if (!($silent)) {
  341. print "\nName of Server: $WebServer
  342. Location of Log: $TransferLog
  343. Output Directory: $Output_Path";
  344. print "
  345. Type            Requests for:            Map To:
  346. =================================================================== 
  347. Aliases:        /                   ==>  $DocumentRoot
  348. ";
  349. if ($#AKA > -1) {
  350. for ($i=0;$i <= $#AKA;$i++) {
  351. printf ("%-16s%-20s==>  %s\n"," ",$AKA[$i],$REALNAME{$AKA[$i]});
  352. }
  353. }
  354. if ($#GO_HTTP > -1) {
  355. printf ("%-16s%-20s==>  %s\n","Redirects:",$GO_HTTP[0],$RDFILES{$GO_HTTP[0]});
  356. for ($i=1;$i <= $#GO_HTTP;$i++) {
  357. printf ("%-16s%-20s==>  %s\n"," ",$GO_HTTP[$i],$RDFILES{$GO_HTTP[$i]});
  358. }
  359. }
  360. printf ("%-16s%-20s==>  ~UserName/%s\n","User Directory:","~",$UserDir) if (defined $UserDir);
  361. print "\n";
  362.  
  363. print "\nType of Report(s): ";
  364. print "Long, " if ($opt_a);
  365. print "Error, " if ($opt_e);
  366. print "Summary, " if ($opt_s);
  367. print "Hosts, " if ($opt_h);
  368. print "Daily, " if ($opt_d);
  369. print "Hourly, " if ($opt_t);
  370. print "Files, " if ($opt_f);
  371. print "\n";
  372. if (defined ($SearchDescriptor)) {
  373.     chop ($SearchDescriptor);
  374.     print "Search Keys: $SearchDescriptor\n\n";
  375.     }
  376. }
  377.  
  378. # Set the output buffer to 1
  379. select ((select(STDOUT),$|=1)[0]);
  380.  
  381. open (LOG,$TransferLog) || die "Couldn't open log file\n";
  382.  
  383. # Process the information in the log.
  384. # Set the array information and determine the maximum value for
  385. #  each array.  The maximum value will be used to set the scale for the
  386. #  the graph.
  387. #  Increment the total number of connections, 
  388. #       the number of connections for that weekday,
  389. #       the number of connections for that hour of the day, and the
  390. #       number of connections for that host.
  391. #       Increment the record number.
  392.  
  393. $RECORD_NUMBER = 1;
  394. $FileMax=1;
  395.  
  396. if (!($silent)) {
  397. print "Sizing your log ...";
  398. # Determine the size (lines) of the log file
  399.         open (WC,"wc -l $TransferLog |") || die "Can't open $TransferLog\n";
  400.         while (<WC>) {
  401.                 ($LINES) = split (/\//,$_);
  402.         }
  403.         close WC;
  404.     print "$LINES entries \n";
  405.     $RunTime = sprintf ("%d %s",(($LINES/24)/60),"minutes");
  406.     $RunTime = sprintf ("%d %s",($RunTime/60),"hours") if ($RunTime >= 60);
  407.     print "Will take approximately $RunTime to process\n";
  408.         $counter = 0;
  409.           $star_percentage = sprintf ("%.2d",$LINES * .02);
  410.     
  411. print "\nProcessing log ...
  412. (each star represents $star_percentage entries)
  413.  
  414. 0    10   20   30   40   50   60   70   80   90  100%
  415. |----|----|----|----|----|----|----|----|----|----|
  416. ";
  417.  
  418. }
  419.  
  420. while (<LOG>) {
  421. undef ($MODpath);
  422. undef ($changes);
  423. if (!($silent)) {
  424.         $counter ++;
  425.     if ($counter % 2) {
  426.         printf ("%c%s",010,"\\");
  427.     }
  428.     else {
  429.         printf ("%c%s",010,"\/");
  430.     }
  431.  
  432.           $counter_percentage = sprintf ("%.2g",$counter/$LINES);
  433.         if ($counter_percentage >= .02) {
  434.         printf ("%c%s",010,"\* ");
  435.         $stars ++;
  436.                 $counter = 0;
  437.         }
  438. }
  439.  
  440.         ($host,$day,$mon,$date,$time,$year,$cmd,$GETpath) = split (/\s+/,$_);
  441.         ($hour,$minutes,$seconds) = split (/:/,$time);
  442. # remove leading [
  443.     $day = substr($day,1,3);
  444. # remove trailing [
  445.     chop $year;
  446.  
  447. # Try to correct for extraneous characters  in 'GET'.  Remove direct
  448. # references to the server and strip out double //'s
  449.     $GETpath =~ s/^$WebServer//;
  450.     $GETpath =~ s/\/\//\//g;
  451.     if ($GETpath =~ /^\/$/) {
  452.         $GETpath = "$DocumentRoot";
  453.     }
  454.  
  455. # If the filename is aliased then convert alias to real name.
  456. foreach $i (0 .. $#AKA) {
  457.     $GETpath =~ s/$AKA[$i]/$REALNAME{$AKA[$i]}/g;
  458. }
  459.  
  460. # If the filename is redirected to another server then convert 
  461. # to redirect.  The MODpath creates a virtual directory for
  462. # clarity in the report.
  463. foreach $i (0 .. $#GO_HTTP) {
  464.     if ($GETpath =~ /$GO_HTTP[$i]/) {
  465.         $file_type = "redirect";
  466.         $GETpath = "/Redirect to $RDFILES{$GO_HTTP[$i]}";
  467.     }
  468. }
  469.  
  470. # If the filename refers to a users' directory then
  471. # split the path, determine the user's home directory
  472. # (perl does not understand the '~' as 'home') and
  473. # reconstruct the path.
  474.     if ($GETpath =~ /^\~/){
  475.         ($user_name,$remainder) = split (/\//,$GETpath);
  476.         $user_name =~ s/\~//;
  477.         $home = (getpwnam($user_name))[7];
  478.         $GETpath =~ s/\~\w+/$home\/$UserDir/;
  479.     }
  480.  
  481. # If it is not an alias, redirect, or user directory then it
  482. # must be relative to DocumentRoot
  483.     $GETpath = "$DocumentRoot$GETpath" if ($GETpath !~ /^\//);
  484.  
  485.     if (($GETpath =~ /\/$/) && ($file_type !~ /redirect/)) {
  486.         $file_type = "directory";
  487.         $GETpath =~ s/\/+$//;
  488.     }
  489.     else {
  490.         $file_type = "file";
  491.     }
  492.  
  493. # If it has had the Server Root prepended to it, then convert
  494. # it to "ServerRoot" for shorthanding the report.
  495.  
  496.     $PRINTpath = $GETpath;
  497.     $PRINTpath =~ s/$ServerRoot/\/ServerRoot/;
  498.     $PRINTpath =~ s/$DocumentRoot/\/DocumentRoot/;
  499.  
  500.         if ($RECORD_NUMBER eq 1) {
  501.                 $start_date = "$mon $date, $year @ $time";
  502.                 $menu_start_date = "$mon $date";
  503.         }
  504. # This ridiculously long conditional just tries to do the right thing with
  505. # possible search key limiters
  506. if (($NO_KEY) || ($NO_DAY_KEY || ($day =~ /$SearchDay/)) && ($NO_DATE_KEY || ($date =~ /$SearchDate/)) && ($NO_TIME_KEY || ($hour =~ /$SearchTime/)) && ($NO_HOST_KEY || ($host =~ /$SearchHost/)) && ($NO_OTHERS_KEY || ($path =~ (/$SearchOthers/)))) { 
  507.                 $connections ++;
  508.                 $Connect{$day} ++;
  509.               $DayMax = $Connect{$day} if ($Connect{$day} > $DayMax);
  510.                 $Connect{$hour} ++;
  511.               $HourMax = $Connect{$hour} if ($Connect{$hour} > $HourMax);
  512.                 $Machines{$host} ++;
  513.               $HostMax = $Machines{$host} if ($Machines{$host} > $HostMax);
  514.  
  515. # If the size of this file hasn't already been determined then try to get
  516. # it's size.  If this returns 0, then it doesn't exist and is therefore an 
  517. # error.
  518. if ($file_type !~ /redirect/) {
  519.         if (!(defined ($SIZE{$GETpath}))) {
  520.             $SIZE{$GETpath} = (-s "$GETpath");
  521.             if (!(defined $SIZE{$GETpath})) {
  522.                 $EXIST_ERRORS{$GETpath} ++;
  523.                 $EXIST_ERRORS ++;
  524.                 next;
  525.             }
  526.             else {
  527.             $SIZE{$GETpath} = sprintf("%9.0d",$SIZE{$GETpath}/1024);
  528.             }
  529.         }
  530.         else {
  531.         $KBYTES{$day} = $KBYTES{$day} + $SIZE{$GETpath};
  532.               $SizeDayMax = $KBYTES{$day} if ($KBYTES{$day} > $SizeDayMax);
  533.         $KBYTES{$hour} = $KBYTES{$hour} + $SIZE{$GETpath};
  534.               $SizeHourMax = $KBYTES{$hour} if ($KBYTES{$hour} > $SizeHourMax);
  535.         }
  536.  
  537. # Get subtotals for each directory in the path name of the file
  538. # This is strictly for the report breakdown.
  539.         undef ($ParentDir);
  540.             @Tree = split (/\//,$PRINTpath);
  541.         for ($i=1;$i < $#Tree;$i++) {
  542.             $ParentDir = $ParentDir . "/" . $Tree[$i];
  543.             $Directory{$ParentDir} ++;
  544.             $KBYTES{$ParentDir} = $KBYTES{$ParentDir} + $SIZE{$GETpath};
  545.         }
  546.          if ($file_type =~ /file/) {
  547.             $TOTAL_KBYTES = $TOTAL_KBYTES + $SIZE{$GETpath};
  548.             $KBYTES{$GETpath} = $KBYTES{$GETpath} + $SIZE{$GETpath};
  549.                         $FILE_ACCESSES ++;
  550.                         $Directory{$GETpath} ++;
  551.                  }
  552.  
  553.                  if ($file_type =~ /directory/) {
  554.                          $DIRECTORY_ACCESSES ++;
  555.                          $Directory{$GETpath} ++;
  556.                  }
  557. }
  558. else {
  559.             $REDIRECTS ++;
  560.             $KBYTES{$GETpath} = "N/A";
  561.                         $Directory{$GETpath} ++;
  562. }
  563.  
  564. $RECORD_NUMBER ++;
  565. }
  566. }
  567.  
  568. close LOG;
  569.  
  570. # This just finishes the thermometer if the
  571. # fractional percentage does not allow printing
  572. # of the last star.
  573. if (!($silent) && ($stars < 51)){
  574.     printf ("%c%s",010,"\*");
  575. }
  576. print "\n\n" if (!($silent));
  577.  
  578.  
  579. # Set the end date variable to that of the last entry in the log.
  580. $end_date = "$mon $date, $year @ $time";
  581. $menu_end_date = "$mon $date";
  582.  
  583. # Output file prefix
  584. $OutFile_Prefix = "$Output_Path/$date$mon$year";
  585.  
  586. # HyperLink path for files
  587. $HyperLink_tmp = $OutFile_Prefix;
  588. $HyperLink_tmp =~ s/$DocumentRoot//;
  589. #$HyperLink_tmp =~ s/(.*) (\.+\/) ($UserDir)/\~\2\/\3/;
  590. $HyperLink_tmp =~ s/(\w*\W*) (\w+\/)($UserDir)/\~\2\/\3/;
  591. $HyperLink_Prefix = "http://$WebServer$HyperLink_tmp";
  592.  
  593. # HyperLink path for Menu Document
  594. $MenuLink = $MenuDoc;
  595. $MenuLink =~ s/$DocumentRoot//;
  596. $MenuDocLink = "http://$WebServer$MenuLink";
  597.  
  598. # This number represents either the number of subdirectory levels to report
  599. # or the top x percentage of host connections depending on the context.
  600. if (defined $opt_v){
  601.     $verbosity_limit = $opt_v;
  602. }
  603. else {
  604.     $verbosity_limit = 100;
  605. }
  606.  
  607. # Summary report
  608. if ($opt_s) {
  609.     $OutFile = $OutFile_Prefix . ".sum";
  610.     $OutFile = $OutFile . ".html" if ($opt_H);
  611.     print "Writing: $OutFile\n" if (!($silent));
  612.     &PRINT_HEADING;
  613.     open (OUTPUT,">> $OutFile") || die "Can't create $OutFile\n";
  614.     if ($opt_H) {
  615.     print OUTPUT "
  616. <TITLE>Access Report Summary</TITLE>
  617. <H1>
  618. Access Report Summary
  619. </H1>
  620. </pre>";
  621.     }
  622.     close OUTPUT;
  623.     &DO_DAILY(summary);
  624.     &DO_HOURLY(summary);
  625.     &DO_FILES(summary);
  626. }
  627.  
  628.  
  629. # Error Report
  630. if ($opt_e) {
  631.     $OutFile = $OutFile_Prefix . ".error";
  632.     $OutFile = $OutFile . ".html" if ($opt_H);
  633.     print "Writing: $OutFile\n" if (!($silent));
  634.     &DO_ERRORS;
  635. }
  636.  
  637. # File Report
  638. if ($opt_f) {
  639.     $OutFile = $OutFile_Prefix . ".files";
  640.     $OutFile = $OutFile . ".html" if ($opt_H);
  641.     print "Writing: $OutFile\n" if (!($silent));
  642.     &DO_FILES(no_summary);
  643. }
  644.  
  645. # Host Report
  646. if ($opt_h) {
  647.     $OutFile = $OutFile_Prefix . ".hosts";
  648.     $OutFile = $OutFile . ".html" if ($opt_H);
  649.     print "Writing: $OutFile\n" if (!($silent));
  650.     &DO_HOSTS(no_summary);
  651. }
  652.  
  653. # Daily Report
  654. if ($opt_d) {
  655.     $OutFile = $OutFile_Prefix . ".daily";
  656.     $OutFile = $OutFile . ".html" if ($opt_H);
  657.     print "Writing: $OutFile\n" if (!($silent));
  658.     &DO_DAILY(no_summary);
  659. }
  660.  
  661. # Time Report
  662. if ($opt_t) {
  663.     $OutFile = $OutFile_Prefix . ".hourly";
  664.     $OutFile = $OutFile . ".html" if ($opt_H);
  665.     print "Writing: $OutFile\n" if (!($silent));
  666.     &DO_HOURLY(no_summary);
  667. }
  668.  
  669. # All
  670. if ($opt_a) {
  671.     $OutFile = $OutFile_Prefix . ".long";
  672.     $OutFile = $OutFile . ".html" if ($opt_H);
  673.     print "Writing: $OutFile\n" if (!($silent));
  674.     &PRINT_HEADING;
  675.     &DO_DAILY(no_summary);
  676.     &DO_HOURLY(no_summary);
  677.     &DO_HOSTS(no_summary);
  678.     &DO_FILES(no_summary);
  679. }
  680.  
  681.  
  682.  
  683. if ($opt_H) {
  684.     if (!(-e "$MenuDoc")) {
  685.     open (MENU_WRITE,"> $MenuDoc")|| die "Can't create Menu Document\n";
  686. print MENU_WRITE "<TITLE>W3 Server Report Menu</TITLE>
  687. </HEAD>
  688. <BODY>
  689.  
  690. <P>
  691. <H1>
  692. World Wide Web server Activity Reports for:</H1>
  693. <UL>\n";
  694.     close MENU_WRITE;
  695.     }    
  696.  
  697. $MenuDocTmp = $MenuDoc . ".tmp";
  698. open (MENU_READ,"$MenuDoc") || die "Can't read Menu Document\n";
  699. open (MENU_WRITE,"> $MenuDocTmp") || die "Can't create temporary Menu Document\n";
  700. while (<MENU_READ>) {
  701.     if (/\<UL\>/) {
  702. print MENU_WRITE "$_\n";
  703. print MENU_WRITE " <LI>$menu_start_date to $menu_end_date: ";
  704. print MENU_WRITE "<A HREF=\"$HyperLink_Prefix.sum.html\">Summary</A>/" if ($opt_s);
  705. print MENU_WRITE "<A HREF=\"$HyperLink_Prefix.files.html\">File Accesses</A>/" if ($opt_f);
  706. print MENU_WRITE "<A HREF=\"$HyperLink_Prefix.hosts.html\">Host Accesses</A>/" if ($opt_h);
  707. print MENU_WRITE "<A HREF=\"$HyperLink_Prefix.error.html\">Errors</A>/" if ($opt_e);
  708. print MENU_WRITE "<A HREF=\"$HyperLink_Prefix.daily.html\">Daily Accesses</A>/" if ($opt_d);
  709. print MENU_WRITE "<A HREF=\"$HyperLink_Prefix.hourly.html\">Hourly Accesses</A>/" if ($opt_t);
  710. print MENU_WRITE "<A HREF=\"$HyperLink_Prefix.long.html\">Full Report</A>/" if ($opt_a);
  711. print MENU_WRITE "\n";
  712.     }
  713.     else {
  714.         print MENU_WRITE $_;
  715.     }
  716. }
  717. close MENU_READ;
  718. close MENU_WRITE;
  719. rename ("$MenuDocTmp","$MenuDoc");
  720. chmod (0644,$MenuDoc);
  721. }
  722.  
  723. sub DO_ERRORS {
  724.     open (OUTPUT,"> $OutFile") || die "Can't create $OutFile\n";
  725.     $TITLE = "Missing File Report";
  726.     &HYPER_LINK(error) if ($opt_H);
  727.  
  728. print OUTPUT "==================================================================\n";
  729. print OUTPUT "            Web Error History\n";
  730. print OUTPUT "              Beginning $start_date\n";
  731. print OUTPUT "              Ending    $end_date\n";
  732. print OUTPUT "==================================================================\n";
  733. print OUTPUT "\n";
  734. print OUTPUT "NON-EXISTING FILES: $EXIST_ERRORS Occurences\n";
  735. printf OUTPUT ("%-55s%9s\n","Filename","Attempts");
  736. print OUTPUT "_" x 70;
  737. print OUTPUT "\n\n";
  738.  
  739. # Sort by number of attempted accesses.
  740. sub by_attempts {
  741.         $EXIST_ERRORS{$b} <=> $EXIST_ERRORS{$a};
  742. }
  743. @ERRORS = keys(%EXIST_ERRORS);
  744. @sortedERRORS = sort by_attempts @ERRORS;
  745.  
  746. foreach $missing_file (@sortedERRORS) {
  747. $print_heading = "/";
  748. # This subroutine tries to split long pathnames on the / to wrap onto the
  749. # next line of the output.
  750. # Create an array consisting of the names in the full path without
  751. # the '/'
  752.         @heading_format = split (/\//,$missing_file);
  753.  
  754.  
  755. # Iterate through this list of file names that defines the path.   If the
  756. # addition of the next filename to the path is longer than 50 characters
  757. # then wrap to the next line.
  758.  
  759.         for ($i=1;$i < $#heading_format;$i++) {
  760.                 $print_heading = $print_heading . $heading_format[$i] . "/";
  761.                 $StringLength = length($print_heading);
  762.                 if ($StringLength > 50){
  763.             printf OUTPUT ("/%-50s\n","$print_heading");
  764.                         $print_heading = "   ";
  765.                 }
  766.         }
  767. $print_heading = $print_heading . $heading_format[$i];
  768. printf OUTPUT ("%-60s%9s\n","$print_heading",$EXIST_ERRORS{$missing_file});
  769.  
  770. }
  771. printf OUTPUT "</pre>\n" if ($opt_H);
  772. close OUTPUT;
  773. }
  774.  
  775. sub DO_DAILY {
  776. # Set an array to convert 3 letter weekday abbreviations to full names.
  777. @weekdays = ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');
  778. open (OUTPUT,">> $OutFile") || die "Can't create $OutFile\n";
  779. $SubTotal=0;
  780. # Print the connections/weekday data
  781. print OUTPUT "\n";
  782. print OUTPUT "<H1>\n" if ($opt_H);
  783. $TITLE =  "Connections & Byte Count Per Week Day\n";
  784. print OUTPUT $TITLE if (!($opt_H));
  785. print OUTPUT "</H1>\n" if ($opt_H);
  786. #$TITLE = "Daily Report";
  787. $arg = pop(@_);
  788. if ($arg =~ /^summary$/) {
  789.     &HYPER_LINK(daily_sum) if ($opt_H);
  790. }
  791. else {
  792.     &HYPER_LINK(daily) if ($opt_H);
  793. }
  794.  
  795.         printf OUTPUT ("%-17s%-30s\n%s\n"," Day","Results ( . -> Connections, * -> Kbytes )","---------------------------------------------------------------------");
  796.  
  797. # Print the output for each record.
  798.  
  799. foreach $heading (@weekdays) {
  800. # Convert the heading for each day (long form) into the short form for
  801. # accessing the array information.
  802. $index = substr($heading,0,3);
  803. # Calculate the number of stars to print for file accesses.
  804.     if ($DayMax > 0 ){
  805.         $Access_graph = '.' x ($Connect{$index} / $DayMax * 50);
  806.     }
  807.     else {
  808.     $graph = "";
  809.     }
  810. # Calculate the number of #'s to print for file size.
  811.     if ($SizeDayMax > 0){
  812.         $Size_graph = '*' x ($KBYTES{$index} / $SizeDayMax * 50);
  813.     }
  814.     else {
  815.     $Size_graph = "";
  816.     }
  817. # Print them.
  818.     if (($index =~ /$SearchDay/) || $NO_DAY_KEY) {
  819.             printf OUTPUT ("%-15s%9s %s\n%-15s%9s %s\n",$heading,$Connect{$index},$Access_graph,"        ",$KBYTES{$index},$Size_graph);
  820.     $SubTotal = $SubTotal + $Connect{$index};
  821.     }
  822. }
  823. print OUTPUT "\n";
  824. print OUTPUT "Total for this Section: $SubTotal\n\n" if !($NO_KEY);
  825. print OUTPUT "</pre>" if ($opt_H);
  826. close OUTPUT;
  827. }
  828.  
  829. sub DO_HOURLY { 
  830. open (OUTPUT,">> $OutFile") || die "Can't create $OutFile\n"; 
  831. $SubTotal=0;
  832. # Iterate through the 'Hours' array to print the hourly information.  The
  833. # first 10 numbers are quoted to preserve the leading 0.
  834. @Hours = ('00','01','02','03','04','05','06','07','08','09',10 .. 23);
  835. print OUTPUT "\n";
  836. print OUTPUT "<H1>\n" if ($opt_H);
  837. $TITLE =  "Connections  & Byte Count Per Hour\n";
  838. print OUTPUT $TITLE if (!($opt_H));
  839. print OUTPUT "</H1>\n" if ($opt_H);
  840. #$TITLE = "Hourly Report";
  841. $arg = pop(@_);
  842. if ($arg =~ /^summary$/) {
  843.     &HYPER_LINK(hourly_sum) if ($opt_H);
  844. }
  845. else {
  846.     &HYPER_LINK(hourly) if ($opt_H);
  847. }
  848.  
  849.         printf OUTPUT ("%-17s%-30s\n%s\n"," Hour","Results ( . -> Connections, * -> Kbytes )","---------------------------------------------------------------------");
  850. foreach $heading (@Hours) {
  851.         if ($HourMax > 0 ){
  852.         $Access_graph = '.' x ($Connect{$heading} / $HourMax * 50);
  853.         }
  854.         else {
  855.         $Access_graph = "";
  856.         }
  857. # Calculate the number of #'s to print for file size.
  858.     if ($SizeHourMax > 0 ){
  859.         $Size_graph = '*' x ($KBYTES{$heading} / $SizeHourMax * 50);
  860.     }
  861.     else {
  862.     $Size_graph = "";
  863.     }
  864.  
  865.     if (($heading =~ /$SearchTime/) || $NO_TIME_KEY) {
  866.     $SubTotal = $SubTotal + $Connect{$heading};
  867. # Change the heading to read 'Midnight' if appropriate
  868.         if ($heading == '00') {
  869.                 printf OUTPUT ("%-15s%9s %s\n%-15s%9s %s\n","Midnight",$Connect{$heading},$Access_graph,"        ",$KBYTES{$heading},$Size_graph);
  870.         }
  871. # Change the heading to read 'Noon' if appropriate
  872.        elsif ($heading == '12') {
  873.                 printf OUTPUT ("%-15s%9s %s\n%-15s%9s %s\n","Noon",$Connect{$heading},$Access_graph,"        ",$KBYTES{$heading},$Size_graph);
  874.         }
  875. # Else just print the hour by number.
  876.         else {
  877.         if ($heading < 12) {
  878.             $modifier = "AM"; 
  879.             $print_heading = $heading;
  880.         }
  881.         else {
  882.             $modifier = "PM"; 
  883.             $print_heading = $heading - 12;
  884.         }
  885.                 printf OUTPUT ("%3s %-11s%9s %s\n%-15s%9s %s\n",$print_heading,$modifier,$Connect{$heading},$Access_graph,"        ",$KBYTES{$heading},$Size_graph);
  886.         }
  887. }
  888. }
  889. print OUTPUT "\n";
  890. print OUTPUT "Total for this Section: $SubTotal\n\n" if !($NO_TIME_KEY);
  891. print OUTPUT "</pre>" if ($opt_H);
  892. close OUTPUT;
  893. }
  894.  
  895. sub DO_FILES {
  896. open (OUTPUT,">> $OutFile") || die "Can't create $OutFile\n";
  897. print OUTPUT "\n";
  898. print OUTPUT "<H1>\n" if ($opt_H);
  899. $arg = pop(@_);
  900. $local_verbosity = $verbosity_limit;
  901. if (($arg =~ /^summary$/) || defined ($opt_v)){
  902.     $TITLE = "Abbreviated Access Report for Directories and Files\n";
  903.     print OUTPUT $TITLE if (!($opt_H));
  904.     $local_verbosity = 2 if (!(defined ($opt_v)));
  905. }
  906. else {
  907.     $TITLE = "Access Report for Directories and Files\n";
  908. print OUTPUT $TITLE if (!($opt_H));
  909. }
  910.  
  911. print OUTPUT "</H1>\n" if ($opt_H);
  912. #$TITLE = "File Access Report";
  913. &HYPER_LINK(file_sum) if (($opt_H) && ($arg =~ /^summary$/));
  914. &HYPER_LINK(file) if (($opt_H) && ($arg =~ /^no_summary$/));
  915.  
  916. $SubTotal=0;
  917. print OUTPUT "\n";
  918. printf OUTPUT ("%s%32s       %s\n%s\n","Directory or File Accessed","Files","Kb","-------------------------------------------------------------------------");
  919. # Set an array of full pathnames
  920. @DIRS = keys(%Directory);
  921.  
  922. # Sort that array.
  923. @sortedDIRS = sort @DIRS;
  924.  
  925. foreach $heading (@sortedDIRS) {
  926. #@previous_heading = "";
  927. $PrintHeading = "";
  928. $subdir = "";
  929. $StringLength = 0;
  930.  
  931. # Create an array consisting of the names in the full path without
  932. # the '/'
  933.         @heading_format = split (/\//,$heading);
  934.     
  935. $PRINT_ME = 1;
  936.  
  937. # Iterate through this list of file names that defines the path.  For each
  938. # name in this path that is the same as the path of the previously printed 
  939. # file name prepend a leading '.' to the name.  
  940. # This is all to prevent the duplication of full pathnames in the output 
  941. # to make it more readable.
  942.  
  943. for ($i=1;$i <= $#heading_format;$i++) {
  944.     $subdir = $subdir . "/" . $heading_format[$i];
  945.     if ($heading_format[$i] eq $previous_heading[$i]) {
  946.         $PrintHeading = "." . $PrintHeading;
  947.     }
  948.     else {
  949.         $PrintHeading = $PrintHeading . $heading_format[$i];
  950.  
  951.         $StringLength = length ($PrintHeading);
  952.         #if ($StringLength > 50){
  953.         #   $PrintHeading = substr ($PrintHeading,0,(47 - $i)) . "...";
  954.         #   $StringLength = 50;
  955.         #}
  956.  
  957. # Insert a line of tildes from the filename to it's data to make viewing easier.
  958. $Spaces = "~" x (57 - ($StringLength + length ($Directory{$subdir})));
  959. $PrintHeading = "$PrintHeading $Spaces ";
  960.  
  961. # Print it.
  962.         if ($i <= $local_verbosity) {
  963. #print STDERR "$subdir\n";
  964.             if ($PRINT_ME || $NO_OTHERS_KEY) {
  965.                $SubTotal = $SubTotal + $Directory{$subdir};
  966.                $KBYTES{$subdir} = ">1" if $KBYTES{$subdir} == 0;
  967.                      printf OUTPUT ("%s%s%9s Kb\n","$PrintHeading",$Directory{$subdir},$KBYTES{$subdir});
  968.             }
  969.         }
  970. $PrintHeading = "." x $i;
  971.     }
  972. }
  973. # Set this to be the previously printed filename.
  974.         @previous_heading = split (/\//,$heading);
  975.     $PRINT_ME = 0;
  976. }
  977. print OUTPUT "\n";
  978. print OUTPUT "Total for this Section: $SubTotal\n\n" if !($NO_KEY);
  979. print OUTPUT "</pre>" if ($opt_H);
  980. close OUTPUT; 
  981. }
  982.  
  983. sub DO_HOSTS {
  984. open (OUTPUT,">> $OutFile") || die "Can't create $OutFile\n";
  985. print OUTPUT "<H1>\n" if ($opt_H);
  986. $TITLE = "Connections per Host\n";
  987. print OUTPUT $TITLE if (!($opt_H));
  988. print OUTPUT "</H1>\n" if ($opt_H);
  989. #$TITLE = "Host Access Report";
  990. $arg = pop(@_);
  991. if ($arg =~ /^summary$/) {
  992.     &HYPER_LINK(hosts_sum) if ($opt_H);
  993. }
  994. else {
  995.     &HYPER_LINK(hosts) if ($opt_H);
  996. }
  997.  
  998. $SubTotal=0;
  999.  
  1000. # Print the name of each host and the number of time they connected.
  1001. sub by_connections {
  1002.     $Machines{$b} <=> $Machines{$a};
  1003. }
  1004. @HOSTS = keys(%Machines);
  1005. @sortedHOSTS = sort by_connections @HOSTS;
  1006.         printf OUTPUT ("%-30s%s\n%s\n","Host ","Number of Connections","---------------------------------------------------------------------");
  1007. foreach $heading (@sortedHOSTS) {
  1008.     if (($heading =~ /$SearchHost/) || $NO_HOST_KEY) {
  1009.         if ($SubTotal < ($connections * ($verbosity_limit)/100)){
  1010.         $SubTotal = $SubTotal + $Machines{$heading};
  1011.                printf OUTPUT ("%-50s%s\n",$heading,$Machines{$heading});
  1012.         }
  1013.     }
  1014. }
  1015. print OUTPUT "\n";
  1016. print OUTPUT "Total for this Section: $SubTotal\n\n" if !($NO_KEY);
  1017. print OUTPUT "</pre>" if ($opt_H);
  1018. close OUTPUT;
  1019. }
  1020.  
  1021.  
  1022. sub PRINT_HEADING {
  1023. #  Print the header
  1024. open (OUTPUT,"> $OutFile") || die "Can't create $OutFile\n";
  1025. print OUTPUT "<pre>" if ($opt_H);
  1026. print OUTPUT "\n\n";
  1027. print OUTPUT "==================================================================\n";
  1028. print OUTPUT "                 Web Usage Report\n";
  1029. print OUTPUT "         Beginning $start_date\n";
  1030. print OUTPUT "         Ending    $end_date\n";
  1031. print OUTPUT "==================================================================\n";
  1032. print OUTPUT "\n";
  1033. printf OUTPUT ("%-40s%8s\n","Total Number of Connections:",$connections);
  1034. printf OUTPUT ("%-40s%8s\n","Total Number of KiloBytes Retrieved:",$TOTAL_KBYTES);
  1035. printf OUTPUT ("%-40s%8s\n","Total Number of Directories Browsed:",$DIRECTORY_ACCESSES);
  1036. printf OUTPUT ("%-40s%8s\n","Total Number of Nonexistent Files:",$EXIST_ERRORS);
  1037. printf OUTPUT ("%-40s%8s\n","Total Number of Redirected Accesses:",$REDIRECTS);
  1038. print OUTPUT "\n";
  1039. close OUTPUT;
  1040. chmod 0644,$OutFile;
  1041. }
  1042.  
  1043. sub HYPER_LINK {
  1044. $THIS_ENTRY = pop(@_);
  1045. print OUTPUT " <pre>\n";
  1046. if (!(@_ =~ /summary/)) {
  1047. print OUTPUT "<TITLE>$TITLE</TITLE>
  1048. <H1>$TITLE</H1>
  1049. ";
  1050. }
  1051. print OUTPUT "See Also: <A HREF=\"$MenuDocLink\">Report Menu</A> / ";
  1052. print OUTPUT "<A HREF=\"$HyperLink_Prefix.long.html\">Full Report</A> /" if (($opt_a) && ($THIS_ENTRY !~ /long/));
  1053. print OUTPUT "<A HREF=\"$HyperLink_Prefix.error.html\">Error Report</A> /" if (($opt_e) && ($THIS_ENTRY !~ /error/));
  1054. print OUTPUT "<A HREF=\"$HyperLink_Prefix.sum.html\">Summary</A> /" if (($opt_s) && ($THIS_ENTRY !~ /sum/));
  1055. print OUTPUT "<A HREF=\"$HyperLink_Prefix.files.html\">Detailed File Accesses</A> /" if (($opt_f)  && ($THIS_ENTRY !~ /^file$/)); 
  1056. print OUTPUT "<A HREF=\"$HyperLink_Prefix.daily.html\">Daily Accesses</A> /" if (($opt_d) && ($THIS_ENTRY !~ /daily/));
  1057. print OUTPUT "<A HREF=\"$HyperLink_Prefix.hourly.html\">Hourly Accesses</A> /" if (($opt_t)&& ($THIS_ENTRY !~ /hourly/));
  1058. print OUTPUT "<A HREF=\"$HyperLink_Prefix.hosts.html\">Host Accesses</A>" if (($opt_h)&& ($THIS_ENTRY !~ /hosts/));
  1059. print OUTPUT "\n";
  1060. }
  1061.